package service

import (
	"context"
	"encoding/json"
	"errors"
	"gLottery/internal/application/dto"
	"gLottery/internal/domain/model"
	"gLottery/internal/domain/repository"
	"gLottery/pkg/jwt"
	"go.uber.org/zap"
	"strconv"
	"time"
)

const (
	userCacheTTL       = 5 * time.Minute // 缓存过期时间
	userCacheKeyPrefix = "user:"
)

type UserService struct {
	userRepo  repository.UserRepository
	cacheRepo repository.CacheRepository // 新增缓存依赖
	jwt       jwt.JWTService
}

// 修改构造函数注入缓存
func NewUserService(
	repo repository.UserRepository,
	cache repository.CacheRepository,
	jwt jwt.JWTService,
) *UserService {
	return &UserService{
		userRepo:  repo,
		cacheRepo: cache,
		jwt:       jwt,
	}
}

// 修改注册方法（清除相关缓存）
func (s *UserService) Register(req *dto.RegisterRequest) error {
	user := &model.User{
		Username: req.Username,
		Email:    req.Email,
		Password: req.Password, // 实际应使用bcrypt加密
	}

	exists, err := s.userRepo.Exists(user.Email)
	if err != nil {
		return err
	}
	if exists {
		return errors.New("email already exists")
	}
	return s.userRepo.Create(user)
}

func (s *UserService) Login(email, password string) (string, error) {
	user, err := s.userRepo.FindByEmail(email)
	if err != nil {
		return "", errors.New("invalid credentials")
	}

	// 这里应该验证密码（示例省略密码哈希验证）
	if user.Password != password {
		return "", errors.New("invalid credentials")
	}

	return s.jwt.GenerateToken(user.ID)
}

// 带缓存的查询方法示例
func (s *UserService) GetProfile(ctx context.Context, userID uint) (*model.User, error) {
	cacheKey := userCacheKeyPrefix + strconv.FormatUint(uint64(userID), 10)

	// 1. 先查缓存
	cached, err := s.cacheRepo.Get(ctx, cacheKey)
	if err != nil {
		return nil, err
	}
	if cached != "" {
		var user model.User
		if err := json.Unmarshal([]byte(cached), &user); err == nil {
			return &user, nil
		}
	}

	// 2. 缓存未命中，查询数据库
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return nil, err
	}

	// 3. 回写缓存
	if err := s.cacheRepo.Set(ctx, cacheKey, user, userCacheTTL); err != nil {
		// 记录日志但继续返回数据
		zap.L().Warn("failed to set user cache",
			zap.Error(err),
			zap.Uint("user_id", userID))
	}

	return user, nil
}

// 新增DTO转换方法
func toResponse(user *model.User) *dto.UserResponse {
	return &dto.UserResponse{
		ID:       user.ID,
		Username: user.Username,
		Email:    user.Email,
	}
}
